package com.community.web.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.community.common.constant.RedisConstant;
import com.community.common.exception.NeusoftException;
import com.community.common.ip.IpHolder;
import com.community.common.result.ResultCodeEnum;
import com.community.common.utils.CodeUtil;
import com.community.common.utils.JwtUtil;
import com.community.model.entity.PortalLoginLog;
import com.community.model.entity.User;
import com.community.model.entity.Wallet;
import com.community.web.user.mapper.PortalLoginLogMapper;
import com.community.web.user.mapper.UserMapper;
import com.community.web.user.mapper.WalletMapper;
import com.community.web.user.service.LoginService;
import com.community.web.user.service.SmsService;
import com.community.web.user.vo.LoginVo;
import com.community.web.user.vo.RegisterVo;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private SmsService smsService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private UserMapper mapper;

    @Autowired
    private PortalLoginLogMapper loginLogMapper;

    @Autowired
    private WalletMapper walletMapper;

    @Override
    public void sendCode(String phone) {
        //1. 检查手机号码是否为空
        if (!StringUtils.hasText(phone)) {
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_PHONE_EMPTY);
        }

        //2. 检查Redis中是否已经存在该手机号码的key
        String key = RedisConstant.USER_LOGIN_PREFIX + phone;
        Boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey) {
            //若存在，则检查其存在的时间
            Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
            if (RedisConstant.USER_LOGIN_CODE_TTL_SEC - expire < RedisConstant.USER_LOGIN_CODE_RESEND_TIME_SEC) {
                //若存在时间不足一分钟，响应发送过于频繁
                throw new NeusoftException(ResultCodeEnum.USER_SEND_SMS_TOO_OFTEN);
            }
        }

        //3.发送短信，并将验证码存入Redis
        String verifyCode = CodeUtil.getRandomCode(6);
        smsService.sendCode(phone, verifyCode);
        redisTemplate.opsForValue().set(key, verifyCode, RedisConstant.USER_LOGIN_CODE_TTL_SEC, TimeUnit.SECONDS);
    }

    @Override
    @Transactional
    public String login(LoginVo loginVo) {
        if (loginVo.getPhone().isEmpty()){
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_PHONE_EMPTY);
        }
        User user = mapper.selectOneByPhone(loginVo.getPhone());
        if (user == null){
            throw new NeusoftException(ResultCodeEnum.USER_ACCOUNT_NOT_EXIST_ERROR);
        }
        if (user.getUserStatus() == 2){
            throw new NeusoftException(ResultCodeEnum.USER_ACCOUNT_DISABLED_ERROR);
        }
        if (!user.getUserPassword().equals(DigestUtils.md5Hex(loginVo.getPassword()))){
            throw new NeusoftException(ResultCodeEnum.USER_ACCOUNT_ERROR);
        }

        //更新登录时间
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(User::getLastLoginTime, LocalDateTime.now());
        updateWrapper.eq(User::getId, user.getId());
        mapper.update(null,updateWrapper);

        //插入登录日志
        PortalLoginLog loginLog = new PortalLoginLog();
        loginLog.setUserId(user.getId());
        loginLog.setLoginIp(IpHolder.getIp());
        loginLogMapper.insert(loginLog);


        String secretKey = "fUY7Zgwdyl9lWmKwqadOnbLcEnHmeB1F";
        long ttlMillis = 3600000;
        HashMap<String, Object> map = new HashMap<>();
        map.put("userId", user.getId());
        map.put("username",user.getUserName());

        return JwtUtil.createJWT(secretKey, ttlMillis, map);
    }

    @Override
    public String getUsername(Long userId) {
        User user = mapper.selectById(userId);
        return user.getUserName();
    }

    @Override
    @Transactional
    public void register(RegisterVo registerVo) {

        if (registerVo.getPhone().isEmpty()){
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_PHONE_EMPTY);
        }
        checkPhone(registerVo.getPhone());

        if (registerVo.getCode().isEmpty()){
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_CODE_EMPTY);
        }
        String code = redisTemplate.opsForValue().get(RedisConstant.USER_LOGIN_PREFIX + registerVo.getPhone());
        if (code == null){
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_CODE_EXPIRED);
        }
        if (!code.equals(registerVo.getCode())){
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_CODE_ERROR);
        }

        if (registerVo.getUserPassword().isEmpty()){
            throw new NeusoftException(ResultCodeEnum.PARAM_ERROR);
        }

        // 生成随机数生成器
        Random random = new Random();

        // 生成一个8位的随机数字字符串
        StringBuilder builder = new StringBuilder(8);
        for (int i = 0; i < 8; i++) {
            builder.append(random.nextInt(10)); // 生成0-9之间的随机整数
        }

        String randomNumber = builder.toString();

        User user = new User();
        user.setUserPassword(DigestUtils.md5Hex(registerVo.getUserPassword()));
        user.setPhone(registerVo.getPhone());
        user.setUserName("新用户" + randomNumber);
        user.setUserStatus(1);

        mapper.insert(user);

        //初始化钱包
        Wallet wallet = new Wallet();
        wallet.setUserId(user.getId());
        wallet.setWalletBalance(new BigDecimal(0));
        walletMapper.insert(wallet);
    }

    @Override
    public void checkPhone(String phone) {
        User user = mapper.selectOneByPhone(phone);
        if (user != null){
            throw new NeusoftException(ResultCodeEnum.USER_ACCOUNT_EXIST_ERROR);
        }
    }

    @Override
    public void checkCode(String code, String phone) {
        if (phone.isEmpty()){
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_PHONE_EMPTY);
        }
        if (code.isEmpty()){
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_CODE_EMPTY);
        }
        String code1 = redisTemplate.opsForValue().get(RedisConstant.USER_LOGIN_PREFIX + phone);
        if (code1 == null){
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_CODE_EXPIRED);
        }
        if (!code1.equals(code)){
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_CODE_ERROR);
        }
    }

    @Override
    public void updatePassword(User user) {
        if (user.getPhone().isEmpty()){
            throw new NeusoftException(ResultCodeEnum.USER_LOGIN_PHONE_EMPTY);
        }
        if (user.getUserPassword().isEmpty()){
            throw new NeusoftException(ResultCodeEnum.PARAM_ERROR);
        }

        User user1 = mapper.selectOneByPhone(user.getPhone());
        if (user1 == null){
            throw new NeusoftException(ResultCodeEnum.USER_ACCOUNT_NOT_EXIST_ERROR);
        }
        if (user1.getUserStatus() == 2){
            throw new NeusoftException(ResultCodeEnum.USER_ACCOUNT_DISABLED_ERROR);
        }

        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getId, user1.getId());
        updateWrapper.set(User::getUserPassword, DigestUtils.md5Hex(user.getUserPassword()));
        mapper.update(null, updateWrapper);
    }

}
